Developer Documentation

QuickTime 4 API Documentation

Inside Macintosh: Imaging with QuickDraw

Previous | Chapter Top | Chapter Contents | Next |

Copying Pixels Between Color Graphics Ports

As explained in the chapter "QuickDraw Drawing," QuickDraw has three primary image-processing routines.

In basic QuickDraw, CopyBits , CopyMask , and CopyDeepMask copy bit images between two basic graphics ports. In Color QuickDraw, you can also use these procedures to copy pixel images between two color graphics ports. Detailed routine descriptions for these procedures appear in the chapter "QuickDraw Drawing." This section provides an overview of how to use the extra capabilities that Color QuickDraw provides for these procedures.

When using CopyBits , CopyMask , and CopyDeepMask to copy images between color graphics ports, you must coerce each port's CGrafPtr data type to a GrafPtr data type, dereference the portBits fields of each, and then pass these "bitmaps" in the srcBits and dstBits parameters. If your application copies a pixel image from a color graphics port called MyColorPort , in the srcBits parameter you could specify GrafPtr(MyColorPort)^.portBits . In a CGrafPort record, the high 2 bits of the portVersion field are set. This field, which shares the same position in a CGrafPort record as the portBits.rowBytes field in a GrafPort record, indicates to these routines that you have passed it a handle to a pixel map rather than a bitmap.

Color QuickDraw's processing sequence of the CopyBits procedure is illustrated in Figure 4-12 . Listing 6-1 in the chapter "Offscreen Graphics Worlds" illustrates how to use CopyBits to transfer an image prepared in an offscreen graphics world to an onscreen color graphics port.

Figure 12 Copying pixel images with the CopyBits procedure

With the CopyMask procedure, you can supply a pixel map to act as a copying mask. The values of pixels in the mask act as weights that proportionally select between source and destination pixel values. The process is shown in Figure 4-13 , and an example of the effect can be seen in Plate 3 at the front of this book. Listing 6-2 in the chapter "Offscreen Graphics Worlds" illustrates how to use CopyMask to mask and copy an image prepared in an offscreen graphics world to an onscreen color graphics port.

Figure 13 Copying pixel images with the CopyMask procedure

The CopyDeepMask procedure combines the capabilities of the CopyBits and CopyMask procedures. With CopyDeepMask you can specify a pixel map mask, a transfer mode, and a mask region, as shown in Figure 4-14 .

Figure 14 Copying pixel images with the CopyDeepMask procedure

On indexed devices, pixel images are always copied using the color table of the source PixMap record for source color information, and using the color table of the current GDevice record for destination color information. The color table attached to the destination PixMap record is ignored. As explained in the chapter "Offscreen Graphics Worlds," if you need to copy to an offscreen PixMap record with characteristics differing from those of the current graphics device, you should create an appropriate offscreen GDevice record and set it as the current graphics device before the copy operation.

When the PixMap record for the mask is 1 bit deep, it has the same effect as a bitmap mask: a black bit in the mask means that the destination pixel is to take the color of the source pixel; a white bit in the mask means that the destination pixel is to retain its current color. When masks have PixMap records with greater pixel depths than 1, Color QuickDraw takes a weighted average between the colors of the source and destination PixMap records. Within each pixel, the calculation is done in RGB color, on a color component basis. A gray PixMap record mask, for example, works like blend mode in a CopyBits procedure. A red mask (that is, one with high values for the red components of all pixels) filters out red values coming from the source pixel image.

Boolean Transfer Modes With Color Pixels

As described in the chapter "QuickDraw Drawing," QuickDraw offers two types of Boolean transfer modes: pattern modes for drawing lines and shapes, and source modes for copying images or drawing text. In basic graphics ports and in color graphics ports with 1-bit pixel maps, these modes describe the interaction between the bits your application draws and the bits that are already in the destination bitmap or 1-bit pixel map. These interactions involve turning the bits on or off--that is, making the pixels black or white.

The Boolean operations on bitmaps and 1-bit pixel maps are described in the chapter "QuickDraw Drawing." When you draw or copy images to and from bitmaps or 1-bit pixel maps, Color QuickDraw behaves in the manner described in that chapter.

When you use pattern modes in pixel maps with depths greater than 1 bit, Color QuickDraw uses the foreground color and background color when transferring bit patterns; for example, the patCopy mode applies the foreground color to every destination pixel that corresponds to a black pixel in a bit pattern, and it applies the background color to every destination pixel that corresponds to a white pixel in a bit pattern. See the description of the PenMode procedure in the chapter "QuickDraw Drawing" for a list that summarizes how the foreground and background colors are applied with pattern modes.

When you use the CopyBits , CopyMask , and CopyDeepMask procedures to transfer images between pixel maps with depths greater than 1 bit, Color QuickDraw performs the Boolean transfer operations in the manner summarized in Table 4-1 . In general, with pixel images you will probably want to use the srcCopy mode or one of the arithmetic transfer modes described in "Arithmetic Transfer Modes," .

Table 1 Boolean source modes with colored pixels 

Source mode

Action on destination pixel

 

If source pixel is black

If source pixel is white

If source pixel is any other color

srcCopy

Apply foreground color

Apply background color

Apply weighted portions of foreground and background colors

notSrcCopy

Apply background color

Apply foreground color

Apply weighted portions of background and foreground colors

srcOr

Apply foreground color

Leave alone

Apply weighted portions of foreground color

notSrcOr

Leave alone

Apply foreground color

Apply weighted portions of foreground color

srcXor

Invert (undefined for colored destination pixel)

Leave alone

Leave alone

notSrcXor

Leave alone

Invert (undefined for colored destination pixel)

Leave alone

srcBic

Apply background color

Leave alone

Apply weighted portions of background color

notSrcBic

Leave alone

Apply background color

Apply weighted portions of background color

When your application draws with a pixel pattern, Color QuickDraw ignores the pattern mode and simply transfers the pattern directly to the pixel map without regard to the foreground and background colors.

When you use the srcCopy mode to transfer a pixel into a pixel map, Color QuickDraw determines how close the color of that pixel is to black, and then assigns this relative amount of foreground color to the destination pixel. Color QuickDraw also determines how close the color of that pixel is to white, and assigns this relative amount of background color to the destination pixel.

To accomplish this, Color QuickDraw first multiplies the relative intensity of each red, green, and blue component of the source pixel by the corresponding value of the red, green, or blue component of the foreground color. It then multiplies the relative intensity of each red, green, and blue component of the source pixel by the corresponding value of the red, green, or blue component of the background color. For each component, Color QuickDraw adds the results and then assigns the new result as the value for the destination pixel's corresponding component.

For example, the pixel in an image might be all red: that is, its red component has a pixel value of $FFFF, and its green and blue components each have pixel values of $0000. The current foreground color might be black (that is, with pixel values of $0000, $0000, $0000 for its components) and its background color might be all white (that is, with pixel values of $FFFF, $FFFF, $FFFF). When that image is copied using the CopyBits procedure and the srcCopy source mode, CopyBits determines that the red component of the source pixel has 100 percent intensity; multiplying this by the intensity of the red component ($0000) of the foreground color produces a value of $0000, and multiplying this by the intensity of the red component ($FFFF) of the background color produces a value of $FFFF. Adding the results of these two operations produces a pixel value of $FFFF for the red component of the destination pixel. Performing similar operations on the green and blue components of the source pixel produces green and blue pixel values of $0000 for the destination pixel. In this way, CopyBits renders the source's all-red pixel as an all-red pixel in the destination pixel map. A source pixel with only 50 percent intensity for its red component and no intensity for its blue and green components would similarly be drawn as a medium red pixel in the destination pixel map.

Color QuickDraw produces similarly weighted destination colors when you use the other Boolean source modes. When you use the srcBic mode to transfer a colored source pixel into a pixel map, for example, CopyBits determines how close the color of that pixel is to black, and then assigns a relative amount of background color to the destination pixel. For this mode, CopyBits does not determine how close the color of the source pixel is to white.

Because Color QuickDraw uses the foreground and background colors instead of black and white when performing its Boolean source operations, the following effects are produced:

As you can see, applying a foreground color other than black or a background color other than white to the pixel can produce an unexpected result. For consistent results, set the foreground color to black and the background color to white before using CopyBits , CopyMask , or CopyDeepMask .

However, by using the RGBForeColor and RGBBackColor procedures to set the foreground and background colors to something other than black and white before using CopyBits , CopyMask , or CopyDeepMask , you can achieve some interesting coloration effects. Plate 2 at the front of this book shows how setting the foreground color to red and the background color to blue and then using the CopyBits procedure turns a grayscale image into shades of red and blue. Listing 4-5 shows the code that produced these two pixel maps.

Listing 5Using CopyBits to produce coloration effects

PROCEDURE MyColorRamp;
VAR
    origPort:                   CGrafPtr;
    origDevice:                 GDHandle;
    myErr:                      QDErr;
    myOffScreenWorld:           GWorldPtr;
    TheColor:                   RGBColor;
    i:                          Integer;
    offPixMapHandle:            PixMapHandle;
    good:                       Boolean;
    myRect:                     Rect;
BEGIN
    GetGWorld(origPort, origDevice);                {save onscreen graphics port}
                                            {create offscreen graphics world}
    myErr := NewGWorld(myOffScreenWorld,
                             0, origPort^.portRect, NIL, NIL, []);
    IF (myOffScreenWorld = NIL) OR (myErr <> noErr) THEN
        ; {handle errors here}
    SetGWorld(myOffScreenWorld, NIL);            {set current graphics port to offscreen}
    offPixMapHandle := GetGWorldPixMap(myOffScreenWorld);
    good := LockPixels(offPixMapHandle);                {lock offscreen pixel map}
    IF NOT good THEN
        ; {handle errors here}
    EraseRect(myOffScreenWorld^.portRect);              {initialize offscreen pixel map}
    FOR i := 0 TO 9 DO
    BEGIN                                               {create gray ramp}
        theColor.red := i * 7168;
        theColor.green := i * 7168;
        theColor.blue := i * 7168;
        RGBForeColor(theColor);
        SetRect(myRect, myOffScreenWorld^.portRect.left, i * 10,
                 myOffScreenWorld^.portRect.right, i * 10 + 10);
        PaintRect(myRect);              {fill offscreen pixel map with gray ramp}
    END;
    SetGWorld(origPort, origDevice);                {restore onscreen graphics port}
    theColor.red := $0000;
    theColor.green := $0000;
    theColor.blue := $FFFF;
    RGBForeColor(theColor);             {make foreground color all blue}
    theColor.red := $FFFF;
    theColor.green := $0000;
    theColor.blue := $0000;
    RGBBackColor(theColor);             {make background color all red}
        {using blue foreground and red background colors, transfer "gray" }
        { ramp to onscreen graphics port}
    CopyBits(GrafPtr(myOffScreenWorld)^.portBits,                   {gray ramp is source}
                GrafPtr(origPort)^.portBits,                        {window is destination}
                myOffScreenWorld^.portRect, origPort^.portRect, srcCopy, NIL);
    UnlockPixels(offPixMapHandle);
    DisposeGWorld(myOffScreenWorld);
END;

Listing 4-5 uses the NewGWorld function, described in the chapter "Offscreen Graphics Worlds," to create an offscreen pixel map. The sample code draws a gray ramp into the offscreen pixel map, which is illustrated on the left side of Plate 2 at the front of this book. Then Listing 4-5 creates an all-blue foreground color and an all-red background color. This sample code then uses the CopyBits procedure to transfer the pixels in the offscreen pixel map to the onscreen window, which is shown on the right side of Plate 2.

Here are some hints for using foreground and background colors and the srcCopy source mode to color a pixel image:

To help make color work well on different screen depths, Color QuickDraw does some validity checking of the foreground and background colors. If your application is drawing to a color graphics port with a pixel depth equal to 1 or 2, and if the foreground and background colors aren't the same but both of them map to the same pixel value, then the foreground color is inverted. This ensures that, for instance, a red image drawn on a green background doesn't map to black on black.

On indexed devices, these source modes produce unexpected colors, because Color QuickDraw performs Boolean operations on the indexes rather than on actual color values, and the resulting index may point to an entirely unrelated color. On direct devices these transfer modes generally do not exhibit rigorous Boolean behavior except when white is set as the background color.

Dithering

With the CopyBits and CopyDeepMask procedures you can use dithering, a technique used by these procedures for mixing existing colors together to create the illusion of a third color that may be unavailable on an indexed device. For example, if you specify dithering when copying a purple image from a 32-bit direct device to an 8-bit indexed device that does not have purple available, these procedures mix blue and red pixels to give the illusion of purple on the 8-bit device.

Dithering is also useful for improving images that you shrink when copying them from a direct device to an indexed device.

On computers running System 7, you can add dithering to any source mode by adding the following constant or the value it represents to the source mode:

CONST ditherCopy     = 64;      {add to source mode for dithering}

For example, specifying srcCopy + ditherCopy in the mode parameter to CopyBits causes CopyBits to dither the image when it copies the image into the destination pixel map.

Dithering has drawbacks. First, dithering slows the drawing operation. Second, a clipped dithering operation does not provide pixel-for-pixel equivalence to the same unclipped dithering operation. When you don't specify a clipping region, for example, CopyDeepMask begins copying the upper-left pixel in your source image and, if necessary, begins calculating how to dither the upper-left pixel and its adjoining pixels in your destination in order to approximate the color of the source pixel. As CopyDeepMask continues copying pixels in this manner, there is a cumulative dithering effect based on the preceding pixels in the source image. If you specify a clipping region to CopyDeepMask , dithering begins with the upper-left pixel in the clipped region; this ignores the cumulative dithering effect that would otherwise occur by starting at the upper-left corner of the source image. In particular, if you clip and dither a region using the srcXor mode, you can't use CopyDeepMask a second time to copy that region back into the destination pixel map in order to erase that region.

If you replace the Color Manager's color search function with your own search function (as described in the chapter "Color Manager" in Inside Macintosh: Advanced Color Imaging ), CopyBits and CopyDeepMask cannot perform dithering. Without dithering, your application does color mapping on a pixel-by-pixel basis. If your source pixel map is composed of indexed pixels, and if you have installed a custom color search function, Color QuickDraw calls your function once for each color in the color table for the source PixMap record. If your source pixel map is composed of direct pixels, Color QuickDraw calls your custom search function for each color in the pixel image for the source PixMap record; with an image of many colors, this can take a long time.

If you specify a destination rectangle that is smaller than the source rectangle when using CopyBits , CopyMask , or CopyDeepMask on a direct device, Color QuickDraw automatically uses an averaging technique to produce the destination pixels, maintaining high-quality images when shrinking them. On indexed devices, Color QuickDraw averages these pixels only if you specify dithering. Using dithering even when shrinking 1-bit images can produce much better representations of the original images.

Arithmetic Transfer Modes

In addition to the Boolean source modes described previously, Color QuickDraw offers a set of transfer modes that perform arithmetic operations on the values of the red, green, and blue components of the source and destination pixels. Although rarely used by applications, these arithmetic transfer modes produce predictable results on indexed devices because they work with RGB colors rather than with color table indexes. These arithmetic transfer modes are represented by the following constants:

CONST
    blend           = 32;   {replace destination pixel with a blend }
                            { of the source and destination pixel }
                            { colors; if the destination is a bitmap or }
                            { 1-bit pixel map, revert to srcCopy mode}
    addPin          = 33;   {replace destination pixel with the sum of }
                            { the source and destination pixel colors-- }
                            { up to a maximum allowable value; if }
                            { the destination is a bitmap or }
                            { 1-bit pixel map, revert to srcBic mode}
    addOver         = 34;   {replace destination pixel with the sum of }
                            { the source and destination pixel colors-- }
                            { but if the value of the red, green, or }
                            { blue component exceeds 65,536, then }
                            { subtract 65,536 from that value; if the }
                            { destination is a bitmap or 1-bit }
                            { pixel map, revert to srcXor mode}
    subPin          = 35;   {replace destination pixel with the }
                            { difference of the source and destination }
                            { pixel colors--but not less than a minimum }
                            { allowable value; if the destination }
                            { is a bitmap or 1-bit pixel map, revert to }
                            { srcOr mode}
    transparent = 36;       {replace the destination pixel with the }
                            { source pixel if the source pixel isn't }
                            { equal to the background color}
    addMax          = 37;   {compare the source and destination pixels, }
                            { and replace the destination pixel with }
                            { the color containing the greater }
                            { saturation of each of the RGB components; }
                            { if the destination is a bitmap or }
                            { 1-bit pixel map, revert to srcBic mode}
    subOver         = 38;   {replace destination pixel with the }
                            { difference of the source and destination }
                            { pixel colors--but if the value of a red, }
                            { green, or blue component is }
                            { less than 0, add the negative result to }
                            { 65,536; if the destination is a bitmap or }
                            { 1-bit pixel map, revert to srcXor mode}
    adMin           = 39;   {compare the source and destination pixels, }
                            { and replace the destination pixel with }
                            { the color containing the lesser }
                            { saturation of each of the RGB components; }
                            { if the destination is a bitmap or }
                            { 1-bit pixel map, revert to srcOr mode}

You can use the arithmetic modes for all drawing operations; that is, your application can pass them in parameters to the PenMode , CopyBits , CopyDeepMask , and TextMode routines. (The TextMode procedure is described in Inside Macintosh: Text .

When you use the arithmetic transfer modes, each drawing routine converts indexed source and destination pixels to their RGB components; performs the arithmetic operation on each pair of red, green, and blue components to provide a new RGB color for the destination pixel; and then assigns the destination a pixel value close to the calculated RGB color.

For indexed pixels, the arithmetic transfer modes obtain the full 48-bit RGB color from the CLUT. For direct pixels, the arithmetic transfer modes use the 15 or 24 bits of the truncated RGB color. Note, however, that because the colors for indexed pixels depend on the set of colors currently loaded into a graphics device's CLUT, arithmetic transfer modes may produce effects that differ between indexed and direct devices.

The arithmetic transfer modes have no coloration effects.

When you use the addPin mode in a basic graphics port, the maximum allowable value for the destination pixel is always white. In a color graphics port, you can assign the maximum allowable value with the OpColor procedure, described on OpColor . Note that the addOver mode is slightly faster than the addPin mode.

When you use the subPin mode in a basic graphics port, the minimum allowable value for the destination pixel is always black. In a color graphics port, you can assign the minimum allowable value with the OpColor procedure. Note that the subOver mode is slightly faster than the subPin mode.

When you use the addMax and adMin modes, Color QuickDraw compares each RGB component of the source and destination pixels independently, so the resulting color isn't necessarily either the source or the destination color.

When you use the blend mode, Color QuickDraw uses this formula to calculate the weighted average of the source and destination pixels, which Color QuickDraw assigns to the destination pixel:

dest = source ¥ weight/65,535 + destination ¥ (1 - weight/65,535)

In this formula, weight is an unsigned value between 0 and 65,535, inclusive. In a basic graphics port, the weight is set to 50 percent gray, so that equal weights of the source and destination RGB components are combined to produce the destination color. In a color graphics port, the weight is an RGBColor record that individually specifies the weights of the red, green, and blue components. You can assign the weight value with the OpColor procedure.

The transparent mode is most useful on indexed devices, which have 8-bit and 4-bit pixel depths, and on black-and-white devices. You can specify the transparent mode in the mode parameter to the TextMode , PenMode , and CopyBits routines. To specify a transparent pattern, add the transparent constant to the patCopy constant:

transparent + patCopy

The transparent mode is optimized to handle source bitmaps with large transparent holes, as an alternative to specifying an unusual clipping region or mask to the CopyMask procedure. Patterns aren't optimized, and may not draw as quickly.

The arithmetic transfer modes are most useful in direct and 8-bit indexed pixels, but work on 4-bit and 2-bit pixels as well. If the destination pixel map is 1 bit deep, the arithmetic transfer mode reverts to a comparable Boolean transfer mode, as shown in Table 4-2 . (The hilite mode is explained in the next section.)

Table 2 Arithmetic modes in a 1-bit environment

Initial arithmetic mode

Resulting source mode

blend

srcCopy

addOver , subOver , hilite

srcXor

addPin , addMax

srcBic

subPin , adMin , transparent

srcOr

Because drawing with the arithmetic modes uses the closest matching colors, and not necessarily exact matches, these modes might not produce the results you expect. For instance, suppose your application uses the srcCopy mode to paint a green pixel on a screen with 4-bit pixel values. Of the 16 colors available, the closest green may contain a small amount of red, as in RGB components of 300 red, 65,535 green, and 0 blue. Then, your application uses addOver mode to paint a red pixel on top of the green pixel, ideally resulting in a yellow pixel. But the red pixel's RGB components are 65,535 red, 0 green, and 0 blue. Adding the red components of the red and green pixels wraps to 300, since the largest representable value is 65,535. In this case, addOver causes no visible change at all. You can prevent the maximum value from wrapping around by using the OpColor procedure to set the maximum allowable color to white, in which the maximum red value is 65,535. Then you can use the addPin mode to produce the desired yellow result.

Note that the arithmetic transfer modes don't call the Color Manager when mapping a requested RGB color to an indexed pixel value. If your application replaces the Color Manager's color-matching routines (which are described in the chapter "Color Manager" in Inside Macintosh: Advanced Color Imaging ), you must not use these modes, or you must maintain the inverse table yourself.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next